package org.jsola.hr.service.impl;

import jodd.util.StringUtil;
import org.jsola.core.Page;
import org.jsola.core.entity.BaseDO;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IUserRoleCompanyDAO;
import org.jsola.hr.dto.UserRoleCompanyAddDTO;
import org.jsola.hr.dto.UserRoleCompanyUpdateDTO;
import org.jsola.hr.entity.UserRoleCompanyDO;
import org.jsola.hr.query.UserRoleCompanyQuery;
import org.jsola.hr.service.IChildCompanyService;
import org.jsola.hr.service.ICompanyService;
import org.jsola.hr.service.IUserRoleCompanyService;
import org.jsola.hr.vo.ChildCompanyListVO;
import org.jsola.hr.vo.UserRoleCompanyListVO;
import org.jsola.hr.vo.UserRoleCompanyVO;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import static org.jsola.hr.constant.HrPermissionConstants.SUPER_COMPANY_ADMIN;

/**
 * 人员分管用工单位
 *
 * @author zhr
 */
@Service("hrUserRoleCompanyServiceImpl")
public class UserRoleCompanyServiceImpl implements IUserRoleCompanyService {

    @Autowired
    private IUserRoleCompanyDAO userRoleCompanyDAO;

    @Autowired
    @Lazy
    private IChildCompanyService childCompanyService;

    @Autowired
    @Lazy
    private ICompanyService companyService;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public UserRoleCompanyVO save(UserRoleCompanyAddDTO userRoleCompanyAddDTO, TokenUser tokenUser) {
        // 转DO
        UserRoleCompanyDO userRoleCompanyDO = userRoleCompanyAddDTO.to(UserRoleCompanyDO.class);
        // 保存
        userRoleCompanyDO = save(userRoleCompanyDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return userRoleCompanyDO.to(UserRoleCompanyVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public List<UserRoleCompanyVO> batchSave(List<UserRoleCompanyAddDTO> userRoleCompanyAddDTOList, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(userRoleCompanyAddDTOList)) {
            return null;
        }
        List<UserRoleCompanyDO> userRoleCompanyDOList = userRoleCompanyAddDTOList
                .parallelStream()
                .map(userRoleCompanyAddDTO -> {
                    UserRoleCompanyDO userRoleCompanyDO = userRoleCompanyAddDTO.to(UserRoleCompanyDO.class);
                    userRoleCompanyDO.preInsert(tokenUser.getUserId());
                    userRoleCompanyDO.setSiteId(tokenUser.getSiteId());
                    return userRoleCompanyDO;
                }).collect(Collectors.toList());
        userRoleCompanyDAO.insertListAndSetId(userRoleCompanyDOList);
        return userRoleCompanyDOList
                .parallelStream()
                .map(userRoleCompanyDO -> userRoleCompanyDO.to(UserRoleCompanyVO.class))
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(UserRoleCompanyUpdateDTO userRoleCompanyUpdateDTO, TokenUser tokenUser) {
        //转DO
        UserRoleCompanyDO userRoleCompanyDO = userRoleCompanyUpdateDTO.to(UserRoleCompanyDO.class);
        //根据主键更新，只更新非null值
        return updateByIdSelective(userRoleCompanyDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... userRoleCompanyIds) {
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) userRoleCompanyIds);
    }


    @Override
    public UserRoleCompanyVO selectById(String userRoleCompanyId, String siteId) {
        UserRoleCompanyDO userRoleCompanyDO = selectDOById(userRoleCompanyId, siteId);
        if (userRoleCompanyDO == null) {
            return null;
        }
        return userRoleCompanyDO.to(UserRoleCompanyVO.class);
    }

    @Override
    public List<UserRoleCompanyListVO> select(UserRoleCompanyQuery userRoleCompanyQuery, String siteId) {
        List<UserRoleCompanyDO> userRoleCompanyDOList = selectDO(userRoleCompanyQuery, siteId);
        if (CollectionUtils.isEmpty(userRoleCompanyDOList)) {
            return userRoleCompanyDOList == null ? null : new ArrayList<>();
        }
        return userRoleCompanyDOList.stream()
                .map(userRoleCompanyDO -> userRoleCompanyDO.to(UserRoleCompanyListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public List<UserRoleCompanyDO> selectBySiteId(String siteId) {

        Example example = new Example(UserRoleCompanyDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        return userRoleCompanyDAO.selectByExample(example);
    }

    @Override
    public List<UserRoleCompanyDO> selectBySiteIdNotValid(String siteId) {
        Example example = new Example(UserRoleCompanyDO.class);
        example.and().andEqualTo("siteId", siteId);
        return userRoleCompanyDAO.selectByExample(example);
    }

    @Override
    public int selectCount(UserRoleCompanyQuery userRoleCompanyQuery, String siteId) {
        Example example = buildExample(userRoleCompanyQuery, siteId);
        return userRoleCompanyDAO.selectCountByExample(example);
    }

    @Override
    public Page<UserRoleCompanyListVO> selectPage(UserRoleCompanyQuery userRoleCompanyQuery, String siteId) {
        Example example = buildExample(userRoleCompanyQuery, siteId);
        Page<UserRoleCompanyDO> page = userRoleCompanyDAO.selectPageByExample(example,
                userRoleCompanyQuery.getPageNo(),
                userRoleCompanyQuery.getPageSize());

        return page.to(UserRoleCompanyListVO.class);
    }

    @Override
    public UserRoleCompanyDO selectDOById(String userRoleCompanyId, String siteId) {
        return listById(userRoleCompanyId, siteId);
    }

    @Override
    public List<UserRoleCompanyDO> selectDO(UserRoleCompanyQuery userRoleCompanyQuery, String siteId) {
        Example example = buildExample(userRoleCompanyQuery, siteId);
        List<UserRoleCompanyDO> userRoleCompanyDOList = userRoleCompanyDAO.selectByExample(example);
        userRoleCompanyDOList = excludeDelete(userRoleCompanyDOList, siteId);
        return userRoleCompanyDOList;
    }

    @Override
    public List<UserRoleCompanyDO> listByUserAndRoleAndChildCompany(String userId, Long roleId, String childCompanyId, String siteId) {
        Example example = new Example(UserRoleCompanyDO.class);
        example.and()
                .andEqualTo("userId", userId)
                .andEqualTo("roleId", roleId)
                .andEqualTo("childCompanyId", childCompanyId)
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        List<UserRoleCompanyDO> userRoleCompanyDOList = userRoleCompanyDAO.selectByExample(example);
        userRoleCompanyDOList = excludeDelete(userRoleCompanyDOList, siteId);
        return userRoleCompanyDOList;
    }

    @Override
    public List<UserRoleCompanyDO> listByUserAndChildCompany(String userId, String childCompanyId, String siteId) {
        Example example = new Example(UserRoleCompanyDO.class);
        example.and()
                .andEqualTo("userId", userId)
                .andEqualTo("childCompanyId", childCompanyId)
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        List<UserRoleCompanyDO> userRoleCompanyDOList = userRoleCompanyDAO.selectByExample(example);
        userRoleCompanyDOList = excludeDelete(userRoleCompanyDOList, siteId);
        return userRoleCompanyDOList;
    }

    @Override
    public List<UserRoleCompanyDO> selectByChildCompany(String childCompanyId, String siteId) {
        Example example = new Example(UserRoleCompanyDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        // 有所有用工单位分组或当前用工单位分组
        example.and()
                .orEqualTo("isAllChildCompany", true)
                .orEqualTo("childCompanyId", childCompanyId);
        List<UserRoleCompanyDO> userRoleCompanyDOList = userRoleCompanyDAO.selectByExample(example);
        userRoleCompanyDOList = excludeDelete(userRoleCompanyDOList, siteId);
        return userRoleCompanyDOList;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void add(String userId, Long roleId, Boolean isAllEmployer, List<String> childCompanyIdList
            , List<String> employerIdList, TokenUser tokenUser) {
        deleteByUserIdAndSiteId(Collections.singletonList(userId), tokenUser.getSiteId());

        List<UserRoleCompanyAddDTO> userRoleCompanyAddDTOList = new ArrayList<>();
        // 全部用工单位

        if (isAllEmployer != null && isAllEmployer) {
            UserRoleCompanyAddDTO userRoleCompanyAddDTO = new UserRoleCompanyAddDTO();
            userRoleCompanyAddDTO.setUserId(userId);
            userRoleCompanyAddDTO.setRoleId(roleId);
            userRoleCompanyAddDTO.setChildCompanyId(SUPER_COMPANY_ADMIN);
            userRoleCompanyAddDTO.setIsAllEmployer(true);
            userRoleCompanyAddDTO.setEmployerId(null);
            userRoleCompanyAddDTO.setIsAllChildCompany(true);
            userRoleCompanyAddDTOList.add(userRoleCompanyAddDTO);
            save(userRoleCompanyAddDTO, tokenUser);
            return;
        }
        // 保存用工单位分组
        if (!CollectionUtils.isEmpty(childCompanyIdList)) {
            childCompanyIdList = childCompanyIdList.parallelStream().distinct().collect(Collectors.toList());
            for (String childCompanyId : childCompanyIdList) {
                UserRoleCompanyAddDTO userRoleCompanyAddDTO = new UserRoleCompanyAddDTO();
                userRoleCompanyAddDTO.setUserId(userId);
                userRoleCompanyAddDTO.setRoleId(roleId);
                userRoleCompanyAddDTO.setChildCompanyId(childCompanyId);
                userRoleCompanyAddDTO.setIsAllEmployer(true);
                userRoleCompanyAddDTO.setEmployerId(null);
                userRoleCompanyAddDTO.setIsAllChildCompany(false);
                userRoleCompanyAddDTOList.add(userRoleCompanyAddDTO);
            }
        }
        // 保存用工单位
        if (!CollectionUtils.isEmpty(employerIdList)) {
            // 去重
            employerIdList = employerIdList.parallelStream().distinct().collect(Collectors.toList());
            for (String employerId : employerIdList) {
                UserRoleCompanyAddDTO userRoleCompanyAddDTO = new UserRoleCompanyAddDTO();
                userRoleCompanyAddDTO.setUserId(userId);
                userRoleCompanyAddDTO.setRoleId(roleId);
                userRoleCompanyAddDTO.setChildCompanyId(null);
                userRoleCompanyAddDTO.setIsAllEmployer(false);
                userRoleCompanyAddDTO.setEmployerId(employerId);
                userRoleCompanyAddDTO.setIsAllChildCompany(false);
                userRoleCompanyAddDTOList.add(userRoleCompanyAddDTO);
            }
        }
        if (CollectionUtils.isEmpty(userRoleCompanyAddDTOList)) {
            return;
        }
        // 批量保存
        batchSave(userRoleCompanyAddDTOList, tokenUser);
    }

    @Override
    public int deleteByUserIdAndSiteId(List<String> userIds, String siteId) {
        if (CollectionUtils.isEmpty(userIds)) {
            return 0;
        }
        // 先删除旧的有权限的
        Example example = new Example(UserRoleCompanyDO.class);
        example.and()
                .andIn("userId", userIds)
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        List<UserRoleCompanyDO> userRoleCompanyDOList = userRoleCompanyDAO.selectByExample(example);
        TokenUser tokenUser = new TokenUser("deleteByUserIdAndSiteId", siteId);
        return deleteByIds(tokenUser, userRoleCompanyDOList.parallelStream().map(BaseDO::getId).toArray(String[]::new));
    }

    @Override
    public List<UserRoleCompanyDO> screenHasRoleUserInCompany(String companyId, String siteId) {
        Example example = new Example(UserRoleCompanyDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        example.and()
                .orEqualTo("employerId", companyId)
                .orEqualTo("isAllEmployer", true);
        List<UserRoleCompanyDO> userRoleCompanyDOList = userRoleCompanyDAO.selectByExample(example);
        userRoleCompanyDOList = excludeDelete(userRoleCompanyDOList, siteId);
        return userRoleCompanyDOList;
    }

    @Override
    public List<UserRoleCompanyDO> selectByUserId(String userId, String siteId) {
        Example example = new Example(UserRoleCompanyDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("userId", userId);
        List<UserRoleCompanyDO> userRoleCompanyDOList = userRoleCompanyDAO.selectByExample(example);
        userRoleCompanyDOList = excludeDelete(userRoleCompanyDOList, siteId);
        return userRoleCompanyDOList;
    }

    @Override
    public List<UserRoleCompanyDO> selectByUserIdAndRoleId(String userId, Long roleId, String siteId) {
        Example example = new Example(UserRoleCompanyDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("roleId", roleId)
                .andEqualTo("userId", userId);
        List<UserRoleCompanyDO> userRoleCompanyDOList = userRoleCompanyDAO.selectByExample(example);
        userRoleCompanyDOList = excludeDelete(userRoleCompanyDOList, siteId);
        return userRoleCompanyDOList;
    }

    @Override
    public List<UserRoleCompanyDO> selectByUserIds(List<String> userIds, String siteId) {
        if (CollectionUtils.isEmpty(userIds)) {
            return new ArrayList<>();
        }
        Example example = new Example(UserRoleCompanyDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andIn("userId", userIds);
        List<UserRoleCompanyDO> userRoleCompanyDOList = userRoleCompanyDAO.selectByExample(example);
        userRoleCompanyDOList = excludeDelete(userRoleCompanyDOList, siteId);
        return userRoleCompanyDOList;
    }


    @Override
    public List<UserRoleCompanyDO> selectByCompanyIdOrGroupIds(List<String> groupIds, String companyId, String siteId) {
        Example example = new Example(UserRoleCompanyDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (!CollectionUtils.isEmpty(groupIds)) {
            //  查询用工单位、所在分组、所有用工单位的分组
            example.and()
                    .orIn("childCompanyId", groupIds)
                    .orEqualTo("employerId", companyId)
                    .orEqualTo("isAllChildCompany", true);
        } else {
            // 查询用工单位、所有用工单位的分组
            example.and()
                    .orEqualTo("employerId", companyId)
                    .orEqualTo("isAllChildCompany", true);
        }
        List<UserRoleCompanyDO> userRoleCompanyDOList = userRoleCompanyDAO.selectByExample(example);
        userRoleCompanyDOList = excludeDelete(userRoleCompanyDOList, siteId);
        return userRoleCompanyDOList;
    }

    @Override
    public List<UserRoleCompanyDO> selectByCompanyIdListOrGroupIds(List<String> groupIds, List<String> companyIdList, String siteId) {
        if (CollectionUtils.isEmpty(companyIdList)) {
            return new ArrayList<>();
        }
        Example example = new Example(UserRoleCompanyDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (!CollectionUtils.isEmpty(groupIds)) {
            example.and()
                    .orIn("childCompanyId", groupIds)
                    .orEqualTo("isAllChildCompany", true);
        } else {
            example.and()
                    .orIn("employerId", companyIdList)
                    .orEqualTo("isAllChildCompany", true);
        }
        return userRoleCompanyDAO.selectByExample(example);
    }

    @Override
    public List<String> selectNotInChildCompanyIdsAndEmployerIds(List<String> childCompanyIds, List<String> employerIds, String siteId) {
        Example example = new Example(UserRoleCompanyDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (!CollectionUtils.isEmpty(childCompanyIds)) {
            example.and()
                    //拥有其他分组的管理员（不在当前登录人的分组下）
                    .orNotIn("childCompanyId", childCompanyIds)
                    //拥有用工单位权限的管理员（isAllEmployer true 表示组，false 表示用工单位）
                    .orEqualTo("isAllEmployer", false)
                    //拥有全部用工单位（全部用工单位 + 全部分组）的管理员
                    .orEqualTo("isAllChildCompany", true);
        }
        if (!CollectionUtils.isEmpty(employerIds)) {
            example.and()
                    //拥有其他用工单位的管理员
                    .orNotIn("employerId", employerIds)
                    //拥有其他组（isAllEmployer true 表示组，false 表示用工单位）
                    .orEqualTo("isAllEmployer", true)
                    //拥有全部用工单位（全部用工单位 + 全部分组）的管理员
                    .orEqualTo("isAllChildCompany", true);
        }
        List<UserRoleCompanyDO> userRoleCompanyDOList = userRoleCompanyDAO.selectByExample(example);
        userRoleCompanyDOList = excludeDelete(userRoleCompanyDOList, siteId);
        if (CollectionUtils.isEmpty(userRoleCompanyDOList)) {
            return new ArrayList<>();
        }
        return userRoleCompanyDOList.parallelStream().map(UserRoleCompanyDO::getUserId).distinct().collect(Collectors.toList());
    }

    @Override
    public List<UserRoleCompanyDO> selectUserByCompanyId(String companyId, String siteId) {

        // 公司所在分组
        List<ChildCompanyListVO> childCompanyListVOList = childCompanyService
                .selectChildCompanyListByCompanyId(companyId, siteId);
        List<String> childCompanyIds = childCompanyListVOList.parallelStream()
                .map(ChildCompanyListVO::getId).collect(Collectors.toList());
        Example example = new Example(UserRoleCompanyDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (CollectionUtils.isEmpty(childCompanyIds)) {
            example.and()
                    // 有总公司权限的
                    .orEqualTo("isAllChildCompany", true)
                    // 或有该用工单位分组的
                    .orEqualTo("employerId", companyId);
        } else {
            example.and()
                    // 有总公司权限的
                    .orEqualTo("isAllChildCompany", true)
                    // 或有该用工单位分组的
                    .orIn("childCompanyId", childCompanyIds)
                    // 或有该用工单位分组的
                    .orEqualTo("employerId", companyId);
        }
        List<UserRoleCompanyDO> userRoleCompanyDOList = userRoleCompanyDAO.selectByExample(example);
        userRoleCompanyDOList = excludeDelete(userRoleCompanyDOList, siteId);
        return userRoleCompanyDOList;
    }

    /**
     * 排除删除的用工单位/分组
     *
     * @param userRoleCompanyDOList 用户权限
     * @param siteId                站点
     */
    private List<UserRoleCompanyDO> excludeDelete(List<UserRoleCompanyDO> userRoleCompanyDOList, String siteId) {
        // 判断是否删除
        // 用工单位分组
        List<String> groupIds = userRoleCompanyDOList.parallelStream()
                .map(UserRoleCompanyDO::getChildCompanyId).collect(Collectors.toList());
        TokenUser tokenUser = new TokenUser();
        tokenUser.setSiteId(siteId);
        List<String> hadGroupIds = childCompanyService.selectByIds(groupIds, tokenUser)
                .parallelStream().map(BaseDO::getId).collect(Collectors.toList());
        List<String> companyIds = userRoleCompanyDOList.parallelStream()
                .map(UserRoleCompanyDO::getEmployerId).collect(Collectors.toList());
        List<String> hadCompanyIds = companyService.selectByIds(companyIds, siteId)
                .parallelStream().map(BaseDO::getId).collect(Collectors.toList());
        return userRoleCompanyDOList.parallelStream().filter(userRoleCompanyDO -> {
            if (userRoleCompanyDO.getIsAllChildCompany() != null && userRoleCompanyDO.getIsAllChildCompany()) {
                return true;
            }
            // 若是组权限
            if (StringUtil.isNotBlank(userRoleCompanyDO.getChildCompanyId())) {
                return hadGroupIds.contains(userRoleCompanyDO.getChildCompanyId());
            }
            // 若是用工单位权限
            if (StringUtil.isNotBlank(userRoleCompanyDO.getEmployerId())) {
                return hadCompanyIds.contains(userRoleCompanyDO.getEmployerId());
            }
            return true;
        }).collect(Collectors.toList());
    }

    /**
     * 根据查询参数，构建example
     *
     * @param userRoleCompanyQuery 查询参数
     * @param siteId               所属站点id
     * @return example
     */
    private Example buildExample(UserRoleCompanyQuery userRoleCompanyQuery, String siteId) {
        Example example = new Example(UserRoleCompanyDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (userRoleCompanyQuery.getUserId() != null) {
            example.and().andEqualTo("userId", userRoleCompanyQuery.getUserId());
        }
        if (userRoleCompanyQuery.getRoleId() != null) {
            example.and().andEqualTo("roleId", userRoleCompanyQuery.getRoleId());
        }
        if (userRoleCompanyQuery.getChildCompanyId() != null) {
            example.and().andEqualTo("childCompanyId", userRoleCompanyQuery.getChildCompanyId());
        }
        if (userRoleCompanyQuery.getEmployerId() != null) {
            example.and().andEqualTo("employerId", userRoleCompanyQuery.getEmployerId());
        }
        if (userRoleCompanyQuery.getIsAllEmployer() != null) {
            example.and().andEqualTo("isAllEmployer", userRoleCompanyQuery.getIsAllEmployer());
        }
        // 排序
        ExampleKit.setExampleOrder(example, userRoleCompanyQuery.getOrders());
        return example;
    }
}




